package com.martin.lib_base.ktx

import android.app.Activity
import com.martin.lib_base.net.NetApply
import dev.utils.DevFinal
import dev.utils.app.permission.PermissionUtils
import dev.utils.common.DateUtils
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flatMapMerge
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.onStart
import org.json.JSONArray
import org.json.JSONObject
import java.util.Date
import kotlin.coroutines.CoroutineContext

/********************************************************************************************
 *  String
 *********************************************************************************************/
/**
 * 非空处理
 * 空数据返回空字符串
 */
fun String?.noNull(replaceStr: String = "") = if (this.isNullOrEmpty()) replaceStr else this

/**
 * 校验数据
 */
fun Any?.verifyData(msg: String): Boolean {
    var nullOrEmpty = this == null
    if (nullOrEmpty) {
        return true
    }
    nullOrEmpty = when (this) {
        is String -> this.isEmpty()
        is Boolean -> !this
        is Int -> this <= 0
        is Float -> this <= 0
        is Double -> this <= 0
        else -> false
    }
    // 弹出提示
    if (nullOrEmpty) {
        showToast(msg)
    }
    return nullOrEmpty
}

/********************************************************************************************
 *  Boolean
 *********************************************************************************************/

fun Boolean?.toInt() = if (this == true) 1 else 0

fun String?.toBoolean() = this == "1"

fun Int?.toBoolean() = this == 1

/********************************************************************************************
 *  Date
 *********************************************************************************************/

/**
 * 格式化日期
 */
fun Date?.formatDate(format: String = DevFinal.TIME.yyMMdd_HYPHEN): String {
    return this?.let { DateUtils.formatDate(it, format) } ?: ""
}

/**
 * 格式化日期时间
 */
fun Date?.formatDateTime(format: String = DevFinal.TIME.yyyyMMddHHmmss_HYPHEN): String {
    return this?.let { DateUtils.formatDate(it, format) } ?: ""
}

fun Long?.formatDateTime(format: String = DevFinal.TIME.yyyyMMddHHmmss_HYPHEN): String {
    return this?.let { DateUtils.formatTime(it, format) } ?: ""
}

fun Long?.formatDate(format: String = DevFinal.TIME.yyMMdd_HYPHEN): String {
    return this?.let { DateUtils.formatTime(it, format) } ?: ""
}

/********************************************************************************************
 *  Json
 *********************************************************************************************/

fun Any?.toJson(format: Boolean = true): String {
    if (this == null) {
        return "{}"
    }
    val json = NetApply.gson.toJson(this)

    // 不格式化直接返回
    if (!format) return json

    if (json.startsWith("{")) {
        return JSONObject(json).toString(2)
    } else if (json.startsWith("[")) {
        return JSONArray(json).toString(2)
    }
    return json
}

/********************************************************************************************
 *  倒计时
 *********************************************************************************************/

fun <T> countdown(
    duration: Long,
    interval: Long,
    context: CoroutineContext = Dispatchers.Default,
    onCountdown: suspend (Long) -> T
): Flow<T> =
    flow { (duration - interval downTo 0 step interval).forEach { emit(it) } }
        .onEach { delay(interval) }
        .onStart { emit(duration) }
        .flatMapMerge { flow { emit(onCountdown(it)) } }
        .flowOn(context)

/********************************************************************************************
 *  处理
 *********************************************************************************************/
/**
 *  虽然有空安全判定,但如果空与非空需要不同的处理,依然要做!=null判定
 *  该方法旨避免判空
 */
inline fun <T, R> T?.handle(handle: (T) -> R?, nullHandle: () -> R? = { null }): R? {
    return if (this != null) handle(this) else nullHandle()
}

/**
 * 尝试执行
 */
inline fun <T, R> T?.tryCatch(handle: (T?) -> R?, cacheHandle: () -> R? = { null }): R? {
    return try {
        handle(this)
    } catch (e: Exception) {
        cacheHandle()
    }
}

///////////////////////////////////////////////////////////////////////////
// 权限
///////////////////////////////////////////////////////////////////////////

/**
 * 申请权限
 */
fun Activity.permission(
    vararg permissions: String,
    onDenied: () -> Unit = {},
    onGranted: () -> Unit = {},
) {
    PermissionUtils.permission(*permissions)
        .callback(object : PermissionUtils.PermissionCallback {
            override fun onGranted() {
                onGranted()
            }

            override fun onDenied(
                grantedList: MutableList<String>?,
                deniedList: MutableList<String>?,
                notFoundList: MutableList<String>?
            ) {
                onDenied()
            }
        })
        .request(this)
}